package heartBeat;

import java.rmi.RemoteException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;

import tool.MysqlApi;

import dataStruct.DataStoreTaskBag;
import dataStruct.EnumHeartBeatType;
import dataStruct.HeartBeatResponse;
import dataStruct.SlaverLoad;
import dataStruct.SlaverStatus;

public class MasterHeartBeatApi implements MasterHeartBeatApiInterface {

	// private static final long serialVersionUID = -3111492742628447261L;

	public MasterHeartBeatApi(
			Map<Integer, SlaverStatus> slaverMap, 
			Queue<String> dataStoreTaskSlaverChunkQueue,
			Map<String, DataStoreTaskBag> dataStoreTaskSlaverChunkMap) 
	{
		MasterHeartBeatApi.slaverMap = slaverMap;
		MasterHeartBeatApi.dataStoreTaskSlaverChunkQueue = dataStoreTaskSlaverChunkQueue;
		MasterHeartBeatApi.dataStoreTaskSlaverChunkMap = dataStoreTaskSlaverChunkMap;
		MasterHeartBeatApi.slaverTaskBufferMap = new HashMap<Integer,  Queue<String>>();
//		 lock = new Object();
	}

	public Boolean updateLastBeatTime(int slaverId) throws RemoteException
	{
		if (slaverMap.containsKey(new Integer(slaverId))) 
		{
			addslaver2Map(slaverId);
			return false;
		}
		else
		{
			addslaver2Map(slaverId);
			System.out.println("slaver [" + slaverId + "] has accessed");
			return true;
		}
	}
	
	public void addslaver2Map(int slaverId) throws RemoteException {
		// TODO Auto-generated method stub
		
		long currentTime = System.currentTimeMillis();
		SlaverStatus slaverStatus = new SlaverStatus(false, currentTime);
		slaverMap.put(new Integer(slaverId), slaverStatus);
		return;
	}
	
	public  HeartBeatResponse heartBeat(
			int slaverId, 
			EnumHeartBeatType heartBeatType, 
			SlaverLoad slaveLoad,
			String info) throws RemoteException, SQLException {
	
		HeartBeatResponse heartBeatResponse = new HeartBeatResponse();
		
		if( updateLastBeatTime(slaverId) == true)
		{
			//register a slaverId into slaver_info database
			MysqlApi.insert_slaver_info(MysqlApi.get_statement(), slaverId, info);
			heartBeatResponse.heartBeatType = EnumHeartBeatType.RESPONSE_RELAX;
			heartBeatResponse.info = "Dear slaver:[" + slaverId + "] login master success";
			return heartBeatResponse;
		}	
		/*
		 * update by SlaverDataStoreApi not by HeartBeatApi
		 */  
		if((heartBeatType == 	EnumHeartBeatType.RESPONSE_DOWNLOAD_FILE_SUCCESS) ||
				(heartBeatType == 	EnumHeartBeatType.RESPONSE_UPLOAD_FILE_SUCCESS))
		{
			dataStoreTaskSlaverChunkQueue.remove(info);
			dataStoreTaskSlaverChunkMap.remove(info);
		}
		else if((heartBeatType == EnumHeartBeatType.RESPONSE_DOWNLOAD_FILE_FAIL) ||
				(heartBeatType == EnumHeartBeatType.RESPONSE_UPLOAD_FILE_FAIL))
		{
			dataStoreTaskSlaverChunkQueue.add(info);
		}
		String dataStoreTaskId;

//		QueueLock.dataStoreTaskSlaverChunkLock.lock();
		dataStoreTaskId = dataStoreTaskSlaverChunkQueue.poll();
//		QueueLock.dataStoreTaskSlaverChunkLock.unlock();

		if(dataStoreTaskId != null)
		{			
			DataStoreTaskBag dataStoreTaskBag = dataStoreTaskSlaverChunkMap.get(dataStoreTaskId);
			dataStoreTaskBag.startTime = System.currentTimeMillis();
			if(dataStoreTaskBag.dataStoreTask.heartBeatType ==EnumHeartBeatType. RESPONSE_DOWNLOAD_FILE)
			{
				heartBeatResponse.heartBeatType = dataStoreTaskBag.dataStoreTask.heartBeatType ;
				heartBeatResponse.info = dataStoreTaskId;
				return heartBeatResponse;
			}
			//debug
			System.out.println(String.format("task is downloading(MasterHeartBeatApi.java)"));
			
			Queue<String> slaverTaskQueue = null;
			if(slaverTaskBufferMap.containsKey(slaverId) == false)
			{
				//debug
				System.out.println(String.format("add pair<slaverId, slaverTaskQueue> to slaverTaskBufferMap(MasterHeartBeatApi.java)"));
				slaverTaskQueue = new LinkedBlockingQueue<String>();
				slaverTaskBufferMap.put(dataStoreTaskBag.slaverId, slaverTaskQueue);
			}
			
			//debug
			System.out.println(String.format("slaverId has exsit in slaverTaskBufferMap(MasterHeartBeatApi.java)"));
			
			 slaverTaskQueue = slaverTaskBufferMap.get(slaverId);
			slaverTaskQueue.add(dataStoreTaskId);

			 if(slaverTaskQueue.isEmpty() == false)
			{
				heartBeatResponse.heartBeatType = dataStoreTaskBag.dataStoreTask.heartBeatType ;
				heartBeatResponse.info =  slaverTaskQueue.poll();
				
				//debug
				System.out.println(String.format("slaverTaskQueue = %s  (MasterHeartBeatApi.java)",heartBeatResponse.info));
				return heartBeatResponse;
			}

			//debug
			System.out.println(String.format("error: slaverTaskQueue.isEmpty()(MasterHeartBeatApi.java)"));
		}
		
		heartBeatResponse.heartBeatType = EnumHeartBeatType.RESPONSE_RELAX;
		heartBeatResponse.info = "Dear slaver:[" + slaverId + "] I have get your heart beat";
		return heartBeatResponse;
	}
	
	private static Map<Integer, SlaverStatus> slaverMap;
	private static Map<Integer,  Queue<String>> slaverTaskBufferMap;
	private static Queue<String> dataStoreTaskSlaverChunkQueue;
	private static Map<String, DataStoreTaskBag> dataStoreTaskSlaverChunkMap;
//	private static Object lock;

}